import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';

class Http {
  static final Http _instance = Http._();

  static Http get instance => Http();

  factory Http() => _instance;

  static late Dio _dio;

  Dio get dio => _dio;

  Http._() {
    // 构造 Dio options
    final BaseOptions options = BaseOptions(
      receiveTimeout: const Duration(seconds: 10),
      connectTimeout: const Duration(seconds: 10),
      sendTimeout: const Duration(seconds: 8),
      responseType: ResponseType.json,
      validateStatus: (_) => true,
      baseUrl: "http://localhost:8000",
    );

    _dio = Dio(options);

    if (kDebugMode) {
      // 日志
      _dio.interceptors.add(PrettyDioLogger(
          requestHeader: true,
          requestBody: true,
          responseBody: true,
          responseHeader: true,
          error: true,
          compact: true,
          maxWidth: 90));
    }

    _dio.interceptors.add(HttpInterceptor());
  }

  BaseError getError(Object obj) {
    // 这里封装了一个 BaseError 类，会根据后端返回的code返回不同的错误类
    switch (obj.runtimeType) {
      case DioException:
        if ((obj as DioException).type == DioExceptionType.badResponse) {
          final response = (obj).response;
          if (response?.statusCode == 401) {
            return NeedLogin();
          } else if (response?.statusCode == 403) {
            return NeedAuth();
          } else if (response?.statusCode == 408) {
            return UserNotExist();
          } else if (response?.statusCode == 409) {
            return PwdNotMatch();
          } else if (response?.statusCode == 405) {
            return UserNameEmpty();
          } else if (response?.statusCode == 406) {
            return PwdEmpty();
          } else {
            return OtherError(
              statusCode: response?.statusCode as int,
              statusMessage: response?.statusMessage as String,
            );
          }
        }
    }

    return OtherError(statusCode: -1, statusMessage: '未知错误');
  }
}

class HttpInterceptor extends Interceptor {
  late DateTime startTime;
  late DateTime endTime;

  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    startTime = DateTime.now();

    if (kDebugMode) {
      print("-------- Http Interceptor start --------");
    }
    return handler.next(options);
  }

  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    endTime = DateTime.now();
    int duration = endTime.difference(startTime).inMilliseconds;

    if (kDebugMode) {
      print("-------- Http Interceptor end: $duration 毫秒 --------");
    }
    if (response.statusCode! > 299 || response.statusCode! < 200) {
      throw DioException(
          requestOptions: RequestOptions(),
          type: DioExceptionType.badResponse,
          response: response,
          message: response.statusMessage);
    }

    return handler.next(response);
  }

  @override
  void onError(DioException err, ErrorInterceptorHandler handler) {
    super.onError(err, handler);
    if (err.type == DioExceptionType.connectionError ||
        err.type == DioExceptionType.connectionTimeout) {
      if (kDebugMode) {
        print('网络错误: ${err.message}');
      }
    } else {
      if (kDebugMode) {
        print('请求错误: ${err.response?.statusCode}-${err.message}');
      }
    }
  }
}

abstract class BaseError {
  final int code;
  final String message;

  BaseError({required this.code, required this.message});
}

class NeedLogin implements BaseError {
  @override
  int get code => 401;

  @override
  String get message => "请先登录";
}

class NeedAuth implements BaseError {
  @override
  int get code => 403;

  @override
  String get message => "非法访问，请使用正确的token";
}

class UserNotExist implements BaseError {
  @override
  int get code => 408;

  @override
  String get message => "用户不存在";
}

class UserNameEmpty implements BaseError {
  @override
  int get code => 405;

  @override
  String get message => "用户名不能为空";
}

class PwdNotMatch implements BaseError {
  @override
  int get code => 409;

  @override
  String get message => "用户密码不正确";
}

class PwdEmpty implements BaseError {
  @override
  int get code => 406;

  @override
  String get message => "用户密码不能为空";
}

class OtherError implements BaseError {
  final int statusCode;
  final String statusMessage;

  OtherError({required this.statusCode, required this.statusMessage});

  @override
  int get code => statusCode;

  @override
  String get message => statusMessage;
}
